package sudoku;

import java.util.ArrayList;

/** 
 * This class represents basic approach to cell on any kind of sudoku grids.
 * @author Taras Basiuk
 * @version 0.1
 */
public abstract class Cell implements Comparable<Cell>, Cloneable{

    /** Value in cell: from 1 to maxValue, if 0 - cell is empty. */
    protected int value;

    /** 
     * If false - cell is generated as part of a problem during
     * start of the game, hence, user can't change it's value.
     */
    protected boolean userAccess;
    
    /** Maximum value to be put in cell.*/
    protected int maxValue;

    /** 
     * List containing all values still available to put in this empty cell,
     * empty if cell is filled with some number.
     */
    protected ArrayList<Integer> possibleValues;
    
    /** 
     * Constructor for cell on the grid with given maximum value. 
     * Sets cell to be empty, available for user input,
     * fills possibleValues with range of values from 1 to maxValue. 
     */
    public Cell(int maxV){

        maxValue = maxV;
        value = 0;
        userAccess = true;
        possibleValues = new ArrayList();

        for (int i=1; i<=maxValue; i++){
            possibleValues.add(i);
        }
    }
    
    /** Constructor for cell on the grid with given value, maximum value and userAccess. */
    public Cell(int maxV, int val, boolean access){
        maxValue = maxV;
        possibleValues = new ArrayList();
        if ( val > 0 && val <= maxValue) {
            value = val;
        } else {
            value = 0;
            for (int i=1; i<=maxValue; i++){
                possibleValues.add(i);
            }
        }
        userAccess = access;
        
    }

    /** 
     * Sets value in cell. Clears 'possibleValues' list.
     * Should not be used to empty cell i.e. put 0 in it.
     * @param value given value to be put in cell.
     * @return successfulness of operation. 
     */
    public boolean setValue(int value){
        
        if ( value > 0 && value <= maxValue){
            this.value = value;
            possibleValues.clear();
            return true;
        }
        return false;
    }

    /** 
     * Sets current value in cell to 0. Fills 'possibleValues' with values 
     * from 1 to maxValue.
     */
    public void eraseValue(){
        this.value = 0;
        for (int i=1; i<=maxValue; i++){
            possibleValues.add(i);
        }
    }

    /** Returns value in the cell.*/
    public int getValue(){
        return value;
    }

    /** 
     * Method sets permission for user to change value in this cell.
     * @param acs New access mode to cell value.
     */
    public void setAccess(boolean acs){
        userAccess = acs;
    }

    /** Method tells if user can change value in this cell. */
    public boolean getAccess(){
        return userAccess;
    }

    /** 
     * Method removes  first(and only) occurrence of given value from
     * possibleValues list.
     * @param concurrent value to be removed from possibleValues list.
     */
    public void excludeFromPossibles(Integer concurent){
        possibleValues.remove(concurent);
    }

    /** 
     * Method returns reference to a copy of possibleValues list.
     * @return LinkedList copy of possibleValues list.
     */
    public ArrayList<Integer> getPossibleValues(){
        return (ArrayList<Integer>)possibleValues.clone();
    }

    /** 
     * Ensures given value will be present in possibleValues list.
     * @param newPossible Value to be added(but not duplicated) to 'possibleValues' list.
     */
    public boolean addToPossibleValues(int newPossible){
        if (newPossible>0 && newPossible <= maxValue && value==0)
            if ( ! possibleValues.contains(newPossible)){
                possibleValues.add(newPossible);
                return true;
            }
        return false;
    }
    
    /** 
     * Method required by Comparable interface. Empty cell with least
     * number of possible values should have highest priority.
     * @param c cell to compare this with.
     */
    @Override
    public int compareTo(Cell c) {

        if (this.possibleValues.size() == c.possibleValues.size())
            return 0;

        if (this.possibleValues.isEmpty()) return 1;
        if (c.possibleValues.isEmpty()) return -1;

        if (this.possibleValues.size() > c.possibleValues.size())
            return 1;

        return -1;
    }
    
    /** Returns string containing value of the cell. */
    @Override
    public String toString(){
        return String.valueOf(value);
    }
 }